﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using GalaSoft.MvvmLight.Messaging;
using GalaSoft.MvvmLight.Threading;
using MouseEventArgs = System.Windows.Forms.MouseEventArgs;
using Rectangle = System.Drawing.Rectangle;
using Timer = System.Threading.Timer;

namespace WindowAutoHide
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded+= OnLoaded;
            DispatcherHelper.Initialize();
        }


        private bool _isCanSet = false;
        private bool _isNoticefyShow = false;//表示从托盘图标双击展示
        private double _border = 10;
        private bool _isHide = false;
        private double _oldTop = 0;
        private double _oldLeft = 0;
        private double _dpiX;
        private double _dpiY;
       
        private void SetIsHide(bool isHide,Rectangle rect)
        {
            if (isHide)
            {
                // _oldLeft = this.Left;
                //  _oldTop = this.Top;
                //  Debug.WriteLine("hide:x: {0}  y:{1}", this.Left, this.Top);
            }
            else
            {
                if (_isHide == isHide) return;
                #region ****************根据隐藏之前的显示值在加上边界判断计算出新的值****************

                var oldLeft = _oldLeft;
                if (oldLeft < rect.Left) oldLeft = rect.Left;
                else if (oldLeft + this.ActualWidth > rect.Right) oldLeft = rect.Right - this.ActualWidth;
                var oldTop = _oldTop;
                if (oldTop + this.ActualHeight > rect.Bottom) oldTop = rect.Bottom - this.ActualHeight;
                //下边超出了，计算后的值还需要计算上边，最终以上边的为准
                if (oldTop < rect.Top)
                {
                    oldTop = rect.Top;
                }

                #endregion
                this.Left = oldLeft;
                this.Top = oldTop;
                //this.Activate();
                this.Topmost = true;
                this.Topmost = false;
            }
            this._isHide = isHide;
        }

        private MouseHook _hook;

        private double GetDpi(float dpi)
        {
            if (dpi == 96) return 1;
            if (dpi == 120) return 1.25;
            if (dpi == 144) return 1.5;
            if (dpi == 192) return 2;
            return 1;
        }

        private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
        {
            using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
            {
                _dpiX =GetDpi(graphics.DpiX);
                _dpiY = GetDpi(graphics.DpiY);
            }
            NotifyIcon icon = new NotifyIcon();
            icon.Icon = new Icon("logo.ico");
            icon.Visible = true;
            icon.DoubleClick += IconOnDoubleClick;
            ShowPosition show=new ShowPosition();
            show.Show();
            _hook = new MouseHook(_dpiX,_dpiY);
            _hook.OnMouseActivity += HookOnOnMouseActivity;
            _hook.Start();
        }


        private Rectangle GetVirtualScreen()
        {
            var rect = SystemInformation.VirtualScreen;
            return new Rectangle(
                (int) (rect.Left / _dpiX),
                (int) (rect.Top / _dpiX),
                (int) (rect.Width / _dpiX),
                (int) (rect.Height / _dpiY));
        }

        private void IconOnDoubleClick(object sender, EventArgs eventArgs)
        {
            this.Activate();
            this.Show();
            if (_isHide)
            {
                _isNoticefyShow = true;
                _isCanSet = false;
            }
            var rect = GetVirtualScreen();
            SetIsHide(false,rect);
        }

        
        private void HookOnOnMouseActivity(object sender, MouseEventArgs e)
        {
            var rect = GetVirtualScreen();
            var str = string.Format(
                @"x:{0} y:{1} 
rectLeft:{2} rectRight:{4} rectTop:{3}  rectBotton:{5}
winLeft:{6} winRight:{8} winTop:{7}  winBotton:{9}",
                e.X, e.Y,
                rect.Left, rect.Top, rect.Right, rect.Bottom,
                this.Left, this.Top, this.Left + this.ActualWidth, this.Top + this.ActualHeight);
            Messenger.Default.Send(str, "position");
            // Debug.WriteLine("x:{0}  y:{1}  click:{2} isMouseDown:{3} left:{4}  top:{5}",
            //    e.X, e.Y, e.Clicks, e.Delta, this.Left, this.Top);
            // return;
            if (_isHide)
            {
                //判断鼠标位置在边框位置里没有
                if (CheckMouseIsWindowBorder(e, rect))
                {
                    //显示
                    SetIsHide(false, rect);
                }
            }
            else
            {
                //思路：双击后移动鼠标后，有两种情况会自动隐藏
                //1.鼠标在离开任务栏后经过窗口后在离开窗口，使得窗口自动隐藏
                //2.鼠标在俩开任务栏后在其它位置单击，出发窗口自动隐藏
                //鼠标离开窗口
                //窗口靠边框
                if (e.Delta == 0 && _isNoticefyShow && _isCanSet == false)
                {
                    //鼠标双击后，移动，并且没有设置
                    _isCanSet = true;
                    return;
                }
                //在鼠标移除托盘图标后，点击鼠标后，将双击状态设置为否，这样就相当于解除双击状态
                if ((e.Delta == 1 || e.Delta == 2) && _isNoticefyShow && _isCanSet)
                {
                    _isNoticefyShow = false;
                    CheckIsHide(e, rect);
                    return;
                }

                if (e.Delta == 0)
                {
                    CheckIsHide(e, rect);
                }
            }
        }

        /// <summary>
        /// 判断鼠标是否在窗体边缘
        /// </summary>
        /// <returns></returns>
        private bool CheckMouseIsWindowBorder(MouseEventArgs e, System.Drawing.Rectangle rect)
        {
            //获取边界的值
            //判断top
            if (e.Y - _border <= rect.Top && e.X >= this.Left && e.X <= (this.Left + this.ActualWidth))
            {
                return true;
            }
            //判断left
            if (e.X - _border<=rect.Left && e.Y >= this.Top && e.Y <= (this.Top + this.ActualHeight))
            {
                //显示
                return true;
            }
            //判断right
            if (this.Left > rect.Left + _border && e.X  + _border >= rect.Right && e.Y >= this.Top &&
                e.Y <= (this.Top + this.ActualHeight))
            {
                return true;
            }

            //SystemInformation.VirtualScreen.
            //判断右边
            return false;
        }

        /// <summary>
        /// 检测是否需要隐藏窗体
        /// </summary>
        /// <param name="e"></param>
        /// <param name="rect"></param>
        private void CheckIsHide(MouseEventArgs e,System.Drawing.Rectangle rect)
        {
            var x = e.X;
            var y = e.Y;
            if (x < rect.Left) x = rect.Left;
            if (x > rect.Right) x = rect.Right;
            if (y < rect.Top) y = rect.Top;
            if (y > rect.Bottom) y = rect.Bottom;

            bool isLeave = !(x >= this.Left && x <= (this.Left + this.ActualWidth) &&
                             y >= this.Top && y <= this.Top + this.ActualHeight);
            if (!isLeave)
            {
                //鼠标在窗体内移动时解除双击状态
                _isNoticefyShow = false;
                return;
            }
            //isLeave=true
            if (_isNoticefyShow == false)
            {
                //顶部判断
                 if (this.Top - _border < rect.Top)
                {
                    SetIsHide(true,rect);
                    //这里修正高度为边界高度，这样做的原因主要是避免鼠标移动到边框上面时出现闪动
                    _oldTop = rect.Top;
                    UpdateLeft(rect);
                }
                //左边判断
                 else if (this.Left - _border < rect.Left)
                {
                    SetIsHide(true, rect);
                    //这里修正左边
                    _oldLeft = rect.Left;
                    this.Left = rect.Left - this.ActualWidth;
                    UpdateTop(rect);
                }
                //右边判断
                else if (this.Left+this.ActualWidth + _border > rect.Right)
                {
                    SetIsHide(true, rect);
                    //修正右边
                    _oldLeft = rect.Right - this.ActualWidth;
                    this.Left = rect.Right;
                   UpdateTop(rect);
                }
            }
        }
        /// <summary>
        /// 修正left
        /// </summary>
        /// <param name="rect"></param>
        private void UpdateLeft(System.Drawing.Rectangle rect)
        {
            //防止左边和右边超出边界
                    var oldLeft = this.Left;
                    if (oldLeft < rect.Left) oldLeft = rect.Left;
                    else if (oldLeft + this.ActualWidth > rect.Right) oldLeft = rect.Right -this.ActualWidth;
                    this.Top = rect.Top - this.ActualHeight;
                    _oldLeft = oldLeft;
                    this.Left = oldLeft;
        }
        /// <summary>
        /// 修正top
        /// </summary>
        /// <param name="rect"></param>
        private void UpdateTop(System.Drawing.Rectangle rect)
        {
             //防止上边和下面超出了边界
                    var oldTop = this.Top;
                    if (oldTop + this.ActualHeight > rect.Bottom) oldTop = rect.Bottom - this.ActualHeight;
                    //下边超出了，计算后的值还需要计算上边，最终以上边的为准
                    if (oldTop < rect.Top)
                    {
                        oldTop = rect.Top;
                    }
                    _oldTop = oldTop;
                    this.Top = _oldTop;
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            this.Hide();
        }
    }
}
